﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using EPiServer;
using EPiServer.Core;
using EPiServer.Core.Html;
using EPiServer.DataAccess;
using EPiServer.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PageTypeBuilder;
using TemplateFoundation.Core;
using TemplateFoundation.PageTypes;
using TemplateFoundation.Tags;
using TemplateFoundation.Tests.Environment;
using TemplateFoundation.Tests.PageTypes;

namespace TemplateFoundation.Tests.UnitTests.EventHandlers
{
    [TestClass]
    public class DefaultPropertyValues
    {
        [TestMethod]
        public void TestDefaultDescriptionOnPublishIfNoDescriptionIsExplicitlySet()
        {
            var newPage = CreateStandardPage();

            newPage.MainBody = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc urna nisi, lacinia nec faucibus eu, molestie eu sem. Phasellus pellentesque augue quis nulla tristique rutrum.</p><p>Nullam porttitor convallis urna in viverra. Curabitur bibendum vehicula dui vel consequat. Pellentesque pellentesque urna ut velit vulputate eu aliquam eros eleifend. Nulla ipsum massa, fringilla id dictum nec, pulvinar non diam. Praesent a consequat dolor. Nullam accumsan, purus nec iaculis mattis, sapien nulla pellentesque dui, sit amet vestibulum leo metus non diam.</p><p>In hac habitasse platea dictumst. Donec eros tortor, mollis eu pharetra in, semper dapibus erat. Aenean consequat pellentesque volutpat. Nunc tellus dui, fringilla a venenatis pulvinar, laoreet rhoncus nisl. Quisque pulvinar felis vel orci malesuada gravida. Cras dolor nulla, rhoncus vel dignissim ut, tristique vulputate magna.</p><p>Nullam consequat sem eros, varius tristique nibh. Donec faucibus est ac magna sodales scelerisque. Pellentesque magna odio, varius at sagittis eu, cursus at nibh.</p>";

            var pageLink = DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var savedPage = (StandardPage)DataFactory.Instance.GetPage(pageLink);

            Assert.AreEqual(
                    TextIndexer.StripHtml(savedPage.MainBody, 160, 20, "..."),
                    savedPage.Description,
                    "Default description was not correctly set to part of the main body content"
                );
        }

        [TestMethod]
        public void TestExplicitlySetDescriptionIsNotOverwrittenWhenPublishing()
        {
            var newPage = CreateStandardPage();

            newPage.MainBody = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc urna nisi, lacinia nec faucibus eu, molestie eu sem. Phasellus pellentesque augue quis nulla tristique rutrum.</p><p>Nullam porttitor convallis urna in viverra. Curabitur bibendum vehicula dui vel consequat. Pellentesque pellentesque urna ut velit vulputate eu aliquam eros eleifend. Nulla ipsum massa, fringilla id dictum nec, pulvinar non diam. Praesent a consequat dolor. Nullam accumsan, purus nec iaculis mattis, sapien nulla pellentesque dui, sit amet vestibulum leo metus non diam.</p><p>In hac habitasse platea dictumst. Donec eros tortor, mollis eu pharetra in, semper dapibus erat. Aenean consequat pellentesque volutpat. Nunc tellus dui, fringilla a venenatis pulvinar, laoreet rhoncus nisl. Quisque pulvinar felis vel orci malesuada gravida. Cras dolor nulla, rhoncus vel dignissim ut, tristique vulputate magna.</p><p>Nullam consequat sem eros, varius tristique nibh. Donec faucibus est ac magna sodales scelerisque. Pellentesque magna odio, varius at sagittis eu, cursus at nibh.</p>";
            newPage.Description = "Explicitly set description";

            var pageLink = DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var savedPage = (StandardPage)DataFactory.Instance.GetPage(pageLink);

            Assert.AreEqual(
                    "Explicitly set description",
                    savedPage.Description,
                    "Explicitly set description did not persist after publishing"
                );
        }

        [TestMethod]
        public void CheckTagsAreAddedAsKeywordsWhenNoKeywordsAreExplicitlySet()
        {
            PageStructure.CreateTagsContainer("Tags", PageReference.RootPage);

            var newPage = (PageTypeBase)CreateStandardPage().CreateWritableClone();

            newPage.Tags = new TagCollection { new Tag("Tag 1"), new Tag("Tag 2"), new Tag("Tag 3") };

            var pageLink = DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var savedPage = (StandardPage)DataFactory.Instance.GetPage(pageLink);

            Assert.AreEqual(
                    "Tag 1,Tag 2,Tag 3",
                    savedPage.Keywords
                );
        }

        [TestMethod]
        public void EnsurePageTitleDefaultValueIsSetProperlyForNewPages()
        {
            var newPage = (PageTypeBase)CreateStandardPage().CreateWritableClone();

            newPage.PageName = "This is the page name";

            if(!string.IsNullOrEmpty(newPage.Title))
            {
                Assert.Fail("Page title property should not have a value at this point");
            }

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (PageTypeBase)DataFactory.Instance.GetPage(newPage.PageLink);

            Assert.IsTrue(publishedPage.Title == publishedPage.PageName, "The page title was not by default set to the page name");
        }

        [TestMethod]
        public void EnsureNonModifiedPageTitleGetsUpdatedWithModifiedPageName()
        {
            var newPage = (PageTypeBase)CreateStandardPage().CreateWritableClone();

            newPage.PageName = "This is the page name";

            if (!string.IsNullOrEmpty(newPage.Title))
            {
                Assert.Fail("Page title property should not have a value at this point");
            }

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (PageTypeBase)DataFactory.Instance.GetPage(newPage.PageLink);

            Assert.IsTrue(publishedPage.Title == publishedPage.PageName, "The page title was not by default set to the page name");

            var clone = publishedPage.CreateWritableClone();

            clone.PageName = "This is the new page name";

            DataFactory.Instance.Save(clone, SaveAction.Publish, AccessLevel.NoAccess);

            var page = (PageTypeBase)DataFactory.Instance.GetPage(clone.PageLink);

            Assert.IsTrue(page.Title == page.PageName, "The page title was not updated properly after changing the page name");
        }

        [TestMethod]
        public void EnsureModifiedPageTitleIsNotOverwrittenWhenPageNameIsChanged()
        {
            var newPage = (PageTypeBase)CreateStandardPage().CreateWritableClone();

            var title = "This will be the title of the page";
            var name = "This is the name of the page";
            var newName = "This is the name of the page after it has been modified";

            newPage.PageName = name;
            newPage.Title = title;

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (PageTypeBase)DataFactory.Instance.GetPage(newPage.PageLink);

            Assert.IsTrue(publishedPage.Title == title, "The page title was incorrectly modified");

            var clone = publishedPage.CreateWritableClone();

            clone.PageName = newName;

            DataFactory.Instance.Save(clone, SaveAction.Publish, AccessLevel.NoAccess);

            var page = (PageTypeBase)DataFactory.Instance.GetPage(clone.PageLink);

            Assert.IsTrue(page.PageName == newName, "The page name was not modified between versions");
            Assert.IsTrue(page.Title == title, "The page title was incorrectly updated when the page name was changed");
        }

        [TestMethod]
        public void TestDefaultDescriptionIsProperlySetAndUpdatedOnPublish()
        {
            var newPage = (StandardPage)CreateStandardPage().CreateWritableClone();

            var name = "This will be the name of the page";
            var mainBody = "<p>This is a lot of content. Some of it will automatically be set as the description of the page, if it hasn't been set explicitly by an editor.</p><p>Here's another paragraph.</p>";
            var mainBodyExcerpt = "This is a lot of content. Some of it will automatically be set as the description of the page, if it hasn't been set explicitly by an editor. Here's another...";

            var modifiedMainBody = "<p>This is modified content. Some of it will automatically be set as the description of the page, if it hasn't been set explicitly by an editor.</p><p>Here's another paragraph.</p>";
            var modifiedMainBodyExcerpt = "This is modified content. Some of it will automatically be set as the description of the page, if it hasn't been set explicitly by an editor. Here's another...";

            var explicitDescription = "This description was set explicitly by the editor";

            newPage.PageName = name;
            newPage.MainBody = mainBody;

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (PageTypeBase)DataFactory.Instance.GetPage(newPage.PageLink);

            // Verify default description is correct
            Assert.IsTrue(publishedPage.Description == mainBodyExcerpt, "The page title was incorrectly modified");

            var firstClone = (StandardPage)publishedPage.CreateWritableClone();

            firstClone.MainBody = modifiedMainBody;

            DataFactory.Instance.Save(firstClone, SaveAction.Publish, AccessLevel.NoAccess);

            var firstModifiedPage = (PageTypeBase)DataFactory.Instance.GetPage(firstClone.PageLink);

            // Verify default description was updated since it hasn't been modified explicitly by editor
            Assert.IsTrue(firstModifiedPage.Description == modifiedMainBodyExcerpt, "The description was not updated when page was published with modified main body");

            var secondClone = (StandardPage)firstModifiedPage.CreateWritableClone();

            secondClone.Description = explicitDescription;

            DataFactory.Instance.Save(secondClone, SaveAction.Publish, AccessLevel.NoAccess);

            var secondModifiedPage = (PageTypeBase)DataFactory.Instance.GetPage(secondClone.PageLink);

            // Verify default description was updated since it hasn't been modified explicitly by editor
            Assert.IsTrue(secondModifiedPage.Description == explicitDescription, "Explicit description was incorrectly overwritten by ETF");

            // Verify description property can be explicitly set to an empty string by an editor
            var thirdClone = (StandardPage)secondModifiedPage.CreateWritableClone();

            thirdClone.Description = " ";

            DataFactory.Instance.Save(thirdClone, SaveAction.Publish, AccessLevel.NoAccess);

            var thirdModifiedPage = (PageTypeBase)DataFactory.Instance.GetPage(thirdClone.PageLink);

            // Verify default description was updated since it hasn't been modified explicitly by editor
            Assert.IsTrue(thirdModifiedPage.Description == null, "Description was set by ETF incorrectly since editor had explicitly removed the description");

        }

        [TestMethod]
        public void EnsureHtmlTagsAreExcludedFromAutomaticallySetDescription()
        {
            var newPage = (StandardPage)CreateStandardPage().CreateWritableClone();

            newPage.MainBody = "<h1>Title</h1><p>Here's some text.</p>";

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (StandardPage)DataFactory.Instance.GetPage(new PageReference(newPage.PageLink.ID));

            Assert.IsTrue(publishedPage.Description.Equals("Title Here's some text."),"Automatic description was not properly set");
        }

        [TestMethod]
        public void EnsureHtmlEncodedCharactersAreExcludedFromAutomaticallySetDescription()
        {
            var newPage = (StandardPage)CreateStandardPage().CreateWritableClone();

            newPage.MainBody = "<p>Here's some&nbsp;text.</p>";

            DataFactory.Instance.Save(newPage, SaveAction.Publish, AccessLevel.NoAccess);

            var publishedPage = (StandardPage)DataFactory.Instance.GetPage(new PageReference(newPage.PageLink.ID));

            Assert.IsTrue(publishedPage.Description.Equals("Here's some text.", StringComparison.OrdinalIgnoreCase), "Automatic description was not properly set when HTML-encoded characters were included");
        }

        [TestMethod]
        public void TestVisibleInMenuIsFalseForDateListingsByDefault()
        {
            var dateListing = DataFactory.Instance.GetDefaultPageData(PageReference.StartPage, PageTypeResolver.Instance.GetPageTypeID(typeof (NewsContainerPage)).Value);

            DataFactory.Instance.Save(dateListing, SaveAction.Publish, AccessLevel.NoAccess);

            Assert.IsFalse(dateListing.VisibleInMenu, "New date listing had VisibleInMenu set to True by default");
        }

        [TestMethod]
        public void TestVisibleInMenuIsFalseForTagListingsByDefault()
        {
            var dateListing = DataFactory.Instance.GetDefaultPageData(PageReference.StartPage, PageTypeResolver.Instance.GetPageTypeID(typeof(TagsContainerPage)).Value);

            DataFactory.Instance.Save(dateListing, SaveAction.Publish, AccessLevel.NoAccess);

            Assert.IsFalse(dateListing.VisibleInMenu, "New tag listing had VisibleInMenu set to True by default");
        }

        [TestMethod]
        public void TestVisibleInMenuCanBeSetToTrueForTagListings()
        {
            // Create new tag listing
            var tagListing = DataFactory.Instance.GetDefaultPageData(PageReference.StartPage, PageTypeResolver.Instance.GetPageTypeID(typeof(TagsContainerPage)).Value);

            DataFactory.Instance.Save(tagListing, SaveAction.Publish, AccessLevel.NoAccess);
   
            // Change its VisibleInMenu property
            var existingTagListing = new PageReference(tagListing.PageLink.ID).GetPage().CreateWritableClone();

            existingTagListing.VisibleInMenu = true;

            DataFactory.Instance.Save(existingTagListing, SaveAction.Publish, AccessLevel.NoAccess);

            var modifiedTagListing = new PageReference(existingTagListing.PageLink.ID).GetPage();

            Assert.IsTrue(modifiedTagListing.VisibleInMenu, "VisibleInMenu property was not successfully changed to True for tag listing");
        }

        [TestMethod]
        public void TestVisibleInMenuCanBeSetToTrueForDateListings()
        {
            // Create new date listing
            var dateListing = DataFactory.Instance.GetDefaultPageData(PageReference.StartPage, PageTypeResolver.Instance.GetPageTypeID(typeof(NewsContainerPage)).Value);

            DataFactory.Instance.Save(dateListing, SaveAction.Publish, AccessLevel.NoAccess);

            // Change its VisibleInMenu property
            var existingDateListing = new PageReference(dateListing.PageLink.ID).GetPage().CreateWritableClone();

            existingDateListing.VisibleInMenu = true;

            DataFactory.Instance.Save(existingDateListing, SaveAction.Publish, AccessLevel.NoAccess);

            var modifiedDateListing = new PageReference(existingDateListing.PageLink.ID).GetPage();

            Assert.IsTrue(modifiedDateListing.VisibleInMenu, "VisibleInMenu property was not successfully changed to True for date listing");
        }

        private StandardPage CreateStandardPage()
        {
            return (StandardPage)DataFactory.Instance.GetDefaultPageData(
                PageReference.StartPage,
                PageTypeResolver.Instance.GetPageTypeID(typeof(StandardPage)).Value);
        }
    }
}
